package org.nhindirect.stagent;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.StringTokenizer;

import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

import org.nhindirect.stagent.EntityPart.EntityPartType;
import org.nhindirect.stagent.ProtocolException.ProtocolError;

public class Message extends MimeEntity 
{
	Collection<InternetAddress> m_to;
	InternetAddress m_from;
    
    public Message()
    {
    }
    
    public Message(Collection<Header> headers)
    {
        if (headers == null)
        {
            throw new IllegalArgumentException();
        }
        
        this.getHeaders().add(headers);
    }
    
    public Header getTo()
    {
       return this.getHeaders().getHeader(Protocol.ToHeader);
    }
    
    public void setTo(Header value)
    {
	    this.getHeaders().setHeader(Protocol.ToHeader, value);
	    this.m_to = null;
    }

    public Header getFrom()
    {
         return this.getHeaders().getHeader(Protocol.FromHeader);
    }
        
    public void setFrom(Header value)
    {

        this.getHeaders().setHeader(Protocol.FromHeader, value);
        this.m_from = null;
        
    }

    public Header getSubject()
    {
        return this.getHeaders().getHeader(Protocol.SubjectHeader);
    }
     
    public void setHeader(Header value)
    {
        this.getHeaders().setHeader(Protocol.SubjectHeader, value);
    }

    public Header getID()
    {
        return this.getHeaders().getHeader(Protocol.MessageIDHeader);
    }
    
    
    public void setID(Header value)
    {
        this.getHeaders().setHeader(Protocol.MessageIDHeader, value);
    }

    public Header getCC()
    {
        return this.getHeaders().getHeader(Protocol.CCHeader);
    }
        
    public void setCC(Header value)
    {
        this.getHeaders().setHeader(Protocol.CCHeader, value);
    }

    public Header getDate()
    {
       return this.getHeaders().getHeader(Protocol.DateHeader);
    }
        
    
    public void setDate(Header value)
    {
       this.getHeaders().setHeader(Protocol.DateHeader, value);
    }
    
    public Collection<InternetAddress> getParsedTo()
    {
        if (this.m_to == null)
        {
            this.m_to = this.toAddressCollection(this.getTo());
        }
        
        return this.m_to;
    }  
    
    public void setParsedTo(Collection<InternetAddress> value)
    {
        if (value == null)
        {
            throw new IllegalArgumentException();
        }
        
        StringBuilder builder = new StringBuilder();
        Iterator<InternetAddress> iter = value.iterator();
        while (iter.hasNext())
        {
        	builder.append(iter.next().getAddress());
        	if (iter.hasNext())
        		builder.append(Protocol.MailAddressSeparator);
        }
        
        this.setTo(new Header(Protocol.ToHeader, builder.toString()));
        this.m_to = value;
    }  
    
    public InternetAddress getParsedFrom()
    {
        if (this.m_from == null)
        {
            this.m_from = this.toMailAddress(this.getFrom());
        }

        return this.m_from;
    }
    
    /// <summary>
    /// The source message has non-MIME headers
    /// Takes the source and creates new Message that contains only items relevant to Mime
    /// </summary>
    /// <returns></returns>
    public MimeEntity extractMimeEntity()
    {
        MimeEntity entity = new MimeEntity();
        
        if (this.hasHeaders())
        {
            //
            // TODO: Optimize this.... 
            //
            entity.setHeaders(this.getHeaders().selectMimeHeaders());
            if (!entity.hasHeaders())
            {
                throw new ProtocolException(ProtocolError.InvalidMimeEntity);
            }
        }
        
        if (this.hasBody())
        {
            entity.setBody(new Body(this.getBody()));
        }
        
        return entity;
    }
    
    public MimeEntity extractEntityForSignature(boolean includeEpilogue)
    {
        if (includeEpilogue || !this.isMultiPart())
        {
            return this.extractMimeEntity();
        }
        
        MimeEntity signableEntity = new MimeEntity();
        signableEntity.setHeaders(this.getHeaders().selectMimeHeaders());
        
        StringSegment content = StringSegment.createNull();
        for (EntityPart part : this.getAllParts())
        {
            if (part.getType() == EntityPartType.Epilogue)
            {
                content = new StringSegment(content.getSource(), content.getStartIndex(), part.getSourceText().getStartIndex() - 1);
            }
            else
            {                
                content.union(part.getSourceText());
            }
        }            
        signableEntity.setBody(new Body(content));
        
        return signableEntity;
    }
            
    InternetAddress toMailAddress(Header header)
    {
    	InternetAddress retVal = null;
    	
        if (header == null)
        {
            return null;
        }

        try
        {
        	retVal = new InternetAddress(header.getValue());
        }
        catch (AddressException e){}
        
        return retVal;
        
    }
    
    
    protected Collection<InternetAddress> toAddressCollection(Header header)
    {
	    if (header == null)
	    {
	        return null;
	    }
    
	    Collection<InternetAddress> collection = new ArrayList<InternetAddress>();
	    StringTokenizer tokenizer = new StringTokenizer(header.getValue(), Protocol.MailAddressSeparator);
	    
	   
	    while (tokenizer.hasMoreTokens())
	    {	try
	    	{
	    		collection.add(new InternetAddress(tokenizer.nextToken()));
	    	}
	    	catch (Exception e)
	    	{
	    		System.err.println("Invalid address format: " + e);
	    	}
	    }

	    return collection;
    }
}
